home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / net / omniORB-2.5.0-src.tar.gz / omniORB-2.5.0-src.tar / omniORB_2.5.0 / include / omnithread.h next >
C/C++ Source or Header  |  1998-04-12  |  13KB  |  472 lines

  1. //                Package : omnithread
  2. // omnithread.h            Created : 7/94 tjr
  3. //
  4. //    Copyright (C) 1994,1995,1996, 1997 Olivetti & Oracle Research Laboratory
  5. //
  6. //    This file is part of the omnithread library
  7. //
  8. //    The omnithread library is free software; you can redistribute it and/or
  9. //    modify it under the terms of the GNU Library General Public
  10. //    License as published by the Free Software Foundation; either
  11. //    version 2 of the License, or (at your option) any later version.
  12. //
  13. //    This library is distributed in the hope that it will be useful,
  14. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16. //    Library General Public License for more details.
  17. //
  18. //    You should have received a copy of the GNU Library General Public
  19. //    License along with this library; if not, write to the Free
  20. //    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
  21. //    02111-1307, USA
  22. //
  23.  
  24. //
  25. // Interface to OMNI thread abstraction.
  26. //
  27. // This file declares classes for threads and synchronisation objects
  28. // (mutexes, condition variables and counting semaphores).
  29. //
  30. // Wherever a seemingly arbitrary choice has had to be made as to the interface
  31. // provided, the intention here has been to be as POSIX-like as possible.  This
  32. // is why there is no semaphore timed wait, for example.
  33. //
  34.  
  35. #ifndef __omnithread_h_
  36. #define __omnithread_h_
  37.  
  38. #ifndef NULL
  39. #define NULL (void*)0
  40. #endif
  41.  
  42. class omni_mutex;
  43. class omni_condition;
  44. class omni_semaphore;
  45. class omni_thread;
  46.  
  47. //
  48. // OMNI_THREAD_EXPOSE can be defined as public or protected to expose the
  49. // implementation class - this may be useful for debugging.  Hopefully this
  50. // won't change the underlying structure which the compiler generates so that
  51. // this can work without recompiling the library.
  52. //
  53.  
  54. #ifndef OMNI_THREAD_EXPOSE
  55. #define OMNI_THREAD_EXPOSE private
  56. #endif
  57.  
  58.  
  59. //
  60. // Include implementation-specific header file.
  61. //
  62. // This must define 4 CPP macros of the form OMNI_x_IMPLEMENTATION for mutex,
  63. // condition variable, semaphore and thread.  Each should define any
  64. // implementation-specific members of the corresponding classes.
  65. //
  66.  
  67.  
  68. #if defined(__arm__) && defined(__atmos__)
  69. #include <omnithread/posix.h>
  70.  
  71. #elif defined(__alpha__) && defined(__osf1__)
  72. #include <omnithread/posix.h>
  73.  
  74. #elif defined(__powerpc__) && defined(__aix__)
  75. #include <omnithread/posix.h>
  76.  
  77. #elif defined(__hpux__)
  78. #include <omnithread/posix.h>
  79.  
  80. #elif defined(__osr5__)
  81. #include <omnithread/posix.h>
  82.  
  83. #elif defined(__WIN32__)
  84. #include <omnithread/nt.h>
  85.  
  86. #ifdef _MSC_VER
  87.  
  88. // Using MSVC++ to compile. If compiling library as a DLL,
  89. // define _OMNITHREAD_DLL. If compiling as a statuc library, define
  90. // _WINSTATIC
  91. // If compiling an application that is to be statically linked to omnithread,
  92. // define _WINSTATIC (if the application is  to be dynamically linked, 
  93. // there is no need to define any of these macros).
  94.  
  95. #if defined (_OMNITHREAD_DLL) && defined(_WINSTATIC)
  96. #error "Both _OMNITHREAD_DLL and _WINSTATIC are defined."
  97. #elif defined(_OMNITHREAD_DLL)
  98. #define _OMNITHREAD_NTDLL_ __declspec(dllexport)
  99. #elif !defined(_WINSTATIC)
  100. #define _OMNITHREAD_NTDLL_ __declspec(dllimport)
  101. #elif defined(_WINSTATIC)
  102. #define _OMNITHREAD_NTDLL_
  103. #endif
  104.  // _OMNITHREAD_DLL && _WINSTATIC
  105.  
  106. #else
  107.  
  108. // Not using MSVC++ to compile
  109. #define _OMNITHREAD_NTDLL_
  110.  
  111. #endif
  112.  // _MSC_VER
  113.  
  114. #elif defined(__sunos__) && (__OSVERSION__ == 5)
  115. #ifdef UsePthread
  116. #include <omnithread/posix.h>
  117. #else
  118. #include <omnithread/solaris.h>
  119. #endif
  120.  
  121. #elif defined(__linux__)
  122. #include <omnithread/posix.h>
  123.  
  124. #elif defined(__nextstep__)
  125. #include <omnithread/mach.h>
  126.  
  127. #elif defined(__VMS)
  128. #include <omnithread/posix.h>
  129.  
  130. #else
  131. #error "No implementation header file"
  132. #endif
  133.  
  134. #if !defined(__WIN32__)
  135. #define _OMNITHREAD_NTDLL_
  136. #endif
  137.  
  138. #if (!defined(OMNI_MUTEX_IMPLEMENTATION) || \
  139.      !defined(OMNI_CONDITION_IMPLEMENTATION) || \
  140.      !defined(OMNI_SEMAPHORE_IMPLEMENTATION) || \
  141.      !defined(OMNI_THREAD_IMPLEMENTATION))
  142. #error "Implementation header file incomplete"
  143. #endif
  144.  
  145.  
  146. //
  147. // This exception is thrown in the event of a fatal error.
  148. //
  149.  
  150. class _OMNITHREAD_NTDLL_ omni_thread_fatal {
  151. public:
  152.     int error;
  153.     omni_thread_fatal(int e = 0) : error(e) {}
  154. };
  155.  
  156.  
  157. //
  158. // This exception is thrown when an operation is invoked with invalid
  159. // arguments.
  160. //
  161.  
  162. class _OMNITHREAD_NTDLL_ omni_thread_invalid {};
  163.  
  164.  
  165. ///////////////////////////////////////////////////////////////////////////
  166. //
  167. // Mutex
  168. //
  169. ///////////////////////////////////////////////////////////////////////////
  170.  
  171. class _OMNITHREAD_NTDLL_ omni_mutex {
  172.  
  173. public:
  174.     omni_mutex(void);
  175.     ~omni_mutex(void);
  176.  
  177.     void lock(void);
  178.     void unlock(void);
  179.     void acquire(void) { lock(); }
  180.     void release(void) { unlock(); }
  181.     // the names lock and unlock are preferred over acquire and release
  182.     // since we are attempting to be as POSIX-like as possible.
  183.  
  184.     friend class omni_condition;
  185.  
  186. OMNI_THREAD_EXPOSE:
  187.     OMNI_MUTEX_IMPLEMENTATION
  188. };
  189.  
  190. //
  191. // As an alternative to:
  192. // {
  193. //   mutex.lock();
  194. //   .....
  195. //   mutex.unlock();
  196. // }
  197. //
  198. // you can use a single instance of the omni_mutex_lock class:
  199. //
  200. // {
  201. //   omni_mutex_lock l(mutex);
  202. //   ....
  203. // }
  204. //
  205. // This has the advantage that mutex.unlock() will be called automatically
  206. // when an exception is thrown.
  207. //
  208.  
  209. class _OMNITHREAD_NTDLL_ omni_mutex_lock {
  210.     omni_mutex& mutex;
  211. public:
  212.     omni_mutex_lock(omni_mutex& m) : mutex(m) { mutex.lock(); }
  213.     ~omni_mutex_lock(void) { mutex.unlock(); }
  214. };
  215.  
  216.  
  217. ///////////////////////////////////////////////////////////////////////////
  218. //
  219. // Condition variable
  220. //
  221. ///////////////////////////////////////////////////////////////////////////
  222.  
  223. class _OMNITHREAD_NTDLL_ omni_condition {
  224.  
  225.     omni_mutex* mutex;
  226.  
  227. public:
  228.     omni_condition(omni_mutex* m);
  229.     // constructor must be given a pointer to an existing mutex. The
  230.     // condition variable is then linked to the mutex, so that there is an
  231.     // implicit unlock and lock around wait() and timed_wait().
  232.  
  233.     ~omni_condition(void);
  234.  
  235.     void wait(void);
  236.     // wait for the condition variable to be signalled.  The mutex is
  237.     // implicitly released before waiting and locked again after waking up.
  238.     // If wait() is called by multiple threads, a signal may wake up more
  239.     // than one thread.  See POSIX threads documentation for details.
  240.  
  241.     int timedwait(unsigned long secs, unsigned long nanosecs = 0);
  242.     // timedwait() is given an absolute time to wait until.  To wait for a
  243.     // relative time from now, use omni_thread::get_time. See POSIX threads
  244.     // documentation for why absolute times are better than relative.
  245.     // Returns 1 (true) if successfully signalled, 0 (false) if time
  246.     // expired.
  247.  
  248.     void signal(void);
  249.     // if one or more threads have called wait(), signal wakes up at least
  250.     // one of them, possibly more.  See POSIX threads documentation for
  251.     // details.
  252.  
  253.     void broadcast(void);
  254.     // broadcast is like signal but wakes all threads which have called
  255.     // wait().
  256.  
  257. OMNI_THREAD_EXPOSE:
  258.     OMNI_CONDITION_IMPLEMENTATION
  259. };
  260.  
  261.  
  262. ///////////////////////////////////////////////////////////////////////////
  263. //
  264. // Counting semaphore
  265. //
  266. ///////////////////////////////////////////////////////////////////////////
  267.  
  268. class _OMNITHREAD_NTDLL_ omni_semaphore {
  269.  
  270. public:
  271.     omni_semaphore(unsigned int initial = 1);
  272.     ~omni_semaphore(void);
  273.  
  274.     void wait(void);
  275.     // if semaphore value is > 0 then decrement it and carry on. If it's
  276.     // already 0 then block.
  277.  
  278.     int trywait(void);
  279.     // if semaphore value is > 0 then decrement it and return 1 (true).
  280.     // If it's already 0 then return 0 (false).
  281.  
  282.     void post(void);
  283.     // if any threads are blocked in wait(), wake one of them up. Otherwise
  284.     // increment the value of the semaphore.
  285.  
  286. OMNI_THREAD_EXPOSE:
  287.     OMNI_SEMAPHORE_IMPLEMENTATION
  288. };
  289.  
  290. //
  291. // A helper class for semaphores, similar to omni_mutex_lock above.
  292. //
  293.  
  294. class _OMNITHREAD_NTDLL_ omni_semaphore_lock {
  295.     omni_semaphore& sem;
  296. public:
  297.     omni_semaphore_lock(omni_semaphore& s) : sem(s) { sem.wait(); }
  298.     ~omni_semaphore_lock(void) { sem.post(); }
  299. };
  300.  
  301.  
  302. ///////////////////////////////////////////////////////////////////////////
  303. //
  304. // Thread
  305. //
  306. ///////////////////////////////////////////////////////////////////////////
  307.  
  308. class _OMNITHREAD_NTDLL_ omni_thread {
  309.  
  310. public:
  311.  
  312.     enum priority_t {
  313.     PRIORITY_LOW,
  314.     PRIORITY_NORMAL,
  315.     PRIORITY_HIGH
  316.     };
  317.  
  318.     enum state_t {
  319.     STATE_NEW,        // thread object exists but thread hasn't
  320.                 // started yet.
  321.     STATE_RUNNING,        // thread is running.
  322.     STATE_TERMINATED    // thread has terminated but storage has not
  323.                 // been reclaimed (i.e. waiting to be joined).
  324.     };
  325.  
  326.     //
  327.     // Constructors set up the thread object but the thread won't start until
  328.     // start() is called. The create method can be used to construct and start
  329.     // a thread in a single call.
  330.     //
  331.  
  332.     omni_thread(void (*fn)(void*), void* arg = NULL,
  333.         priority_t pri = PRIORITY_NORMAL);
  334.     omni_thread(void* (*fn)(void*), void* arg = NULL,
  335.         priority_t pri = PRIORITY_NORMAL);
  336.     // these constructors create a thread which will run the given function
  337.     // when start() is called.  The thread will be detached if given a
  338.     // function with void return type, undetached if given a function
  339.     // returning void*. If a thread is detached, storage for the thread is
  340.     // reclaimed automatically on termination. Only an undetached thread
  341.     // can be joined.
  342.  
  343.     void start(void);
  344.     // start() causes a thread created with one of the constructors to
  345.     // start executing the appropriate function.
  346.  
  347. protected:
  348.  
  349.     omni_thread(void* arg = NULL, priority_t pri = PRIORITY_NORMAL);
  350.     // this constructor is used in a derived class.  The thread will
  351.     // execute the run() or run_undetached() member functions depending on
  352.     // whether start() or start_undetached() is called respectively.
  353.  
  354.     void start_undetached(void);
  355.     // can be used with the above constructor in a derived class to cause
  356.     // the thread to be undetached.  In this case the thread executes the
  357.     // run_undetached member function.
  358.  
  359.     virtual ~omni_thread(void);
  360.     // destructor cannot be called by user (except via a derived class).
  361.     // Use exit() or cancel() instead. This also means a thread object must
  362.     // be allocated with new - it cannot be statically or automatically
  363.     // allocated. The destructor of a class that inherits from omni_thread
  364.     // shouldn't be public either (otherwise the thread object can be
  365.     // destroyed while the underlying thread is still running).
  366.  
  367. public:
  368.  
  369.     void join(void**);
  370.     // join causes the calling thread to wait for another's completion,
  371.     // putting the return value in the variable of type void* whose address
  372.     // is given (unless passed a null pointer). Only undetached threads
  373.     // may be joined. Storage for the thread will be reclaimed.
  374.  
  375.     void set_priority(priority_t);
  376.     // set the priority of the thread.
  377.  
  378.     static omni_thread* create(void (*fn)(void*), void* arg = NULL,
  379.                    priority_t pri = PRIORITY_NORMAL);
  380.     static omni_thread* create(void* (*fn)(void*), void* arg = NULL,
  381.                    priority_t pri = PRIORITY_NORMAL);
  382.     // create spawns a new thread executing the given function with the
  383.     // given argument at the given priority. Returns a pointer to the
  384.     // thread object. It simply constructs a new thread object then calls
  385.     // start.
  386.  
  387.     static void exit(void* return_value = NULL);
  388.     // causes the calling thread to terminate.
  389.  
  390.     static omni_thread* self(void);
  391.     // returns the calling thread's omni_thread object.
  392.  
  393.     static void yield(void);
  394.     // allows another thread to run.
  395.  
  396.     static void sleep(unsigned long secs, unsigned long nanosecs = 0);
  397.     // sleeps for the given time.
  398.  
  399.     static void get_time(unsigned long* abs_sec, unsigned long* abs_nsec,
  400.              unsigned long rel_sec = 0, unsigned long rel_nsec=0);
  401.     // calculates an absolute time in seconds and nanoseconds, suitable for
  402.     // use in timed_waits on condition variables, which is the current time
  403.     // plus the given relative offset.
  404.  
  405. private:
  406.  
  407.     virtual void run(void* arg) {}
  408.     virtual void* run_undetached(void* arg) { return NULL; }
  409.     // can be overridden in a derived class.  When constructed using the
  410.     // the constructor omni_thread(void*, priority_t), these functions are
  411.     // called by start() and start_undetached() respectively.
  412.  
  413.     void common_constructor(void* arg, priority_t pri, int det);
  414.     // implements the common parts of the constructors.
  415.  
  416.     omni_mutex mutex;
  417.     // used to protect any members which can change after construction,
  418.     // i.e. the following 2 members:
  419.  
  420.     state_t _state;
  421.     priority_t _priority;
  422.  
  423.     static omni_mutex* next_id_mutex;
  424.     static int next_id;
  425.     int _id;
  426.  
  427.     void (*fn_void)(void*);
  428.     void* (*fn_ret)(void*);
  429.     void* thread_arg;
  430.     int detached;
  431.  
  432. public:
  433.  
  434.     priority_t priority(void) {
  435.  
  436.     // return this thread's priority.
  437.  
  438.     omni_mutex_lock l(mutex);
  439.     return _priority;
  440.     }
  441.  
  442.     state_t state(void) {
  443.  
  444.     // return thread state (invalid, new, running or terminated).
  445.  
  446.     omni_mutex_lock l(mutex);
  447.     return _state;
  448.     }
  449.  
  450.     int id(void) { return _id; }
  451.     // return unique thread id within the current process.
  452.  
  453.  
  454.     // This class plus the instance of it declared below allows us to execute
  455.     // some initialisation code before main() is called.
  456.  
  457.     class _OMNITHREAD_NTDLL_ init_t {
  458.     static int count;
  459.     public:
  460.     init_t(void);
  461.     };
  462.  
  463.     friend class init_t;
  464.  
  465. OMNI_THREAD_EXPOSE:
  466.     OMNI_THREAD_IMPLEMENTATION
  467. };
  468.  
  469. static omni_thread::init_t omni_thread_init;
  470.  
  471. #endif
  472.